# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
import json
import time
from typing import List
from tortoise.expressions import Q
from hypertext import PagingResult
from exception import AppException
from common.utils.urls import UrlUtil
from common.utils.times import TimeUtil
from common.utils.config import ConfigUtil
from common.models.draws import DrawsSquareModel
from common.models.draws import DrawsRecordsModel
from common.models.draws import DrawsCollectModel
from apps.api.schemas.apply.draws import record_schema as schema


class DrawsRecordService:
    """ 绘画记录服务类 """

    @classmethod
    async def lists(cls, user_id: int, params: schema.DrawsRecordSearchIn) -> PagingResult[schema.DrawsRecordsVo]:
        """
        绘画记录列表

        Args:
            user_id (int): 用户ID
            params (schema.DrawsRecordSearchIn): 搜索参数

        Returns:
            PagingResult[schema.DrawsRecordLists]

        Author:
            zero
        """
        # 查询条件
        where = [Q(engine=params.engine), Q(user_id=user_id), Q(is_delete=0)]
        if params.status and int(params.status) > 0:
            where.append(Q(status=int(params.status)))

        # 查询数据
        _model = DrawsRecordsModel.filter(*where).order_by("-id")
        _pager = await DrawsRecordsModel.paginate(
            model=_model,
            page_no=params.page_no,
            page_size=params.page_size
        )

        # 广场查询
        record_ids = [item["id"] for item in _pager.lists]
        squares = await DrawsSquareModel.querySquareDictsByRecordId(record_ids)

        # 处理列表
        _lists = []
        for item in _pager.lists:
            # 绘图操作: ["upsample1", "upsample2", ...]
            create_time: int = TimeUtil.date_to_timestamp(item["create_time"])
            able = cls._handle_able_actions(item["able_actions"], create_time)
            # 广场状态: [-1=未分享,-2=被隐藏,0=待审核,1=通过,2=拒绝]
            square = squares.get(item["id"], {})
            share_status = square.get("audit_status", -1)
            if share_status == 0 and square.get("is_enable") == 0:
                share_status = - 2

            _lists.append(schema.DrawsRecordsVo(
                code=item["code"],
                engine=item["engine"],
                type=item["type"],
                scale=item["scale"],
                model=item["model"],
                version=item["version"],
                prompt_in=item["prompt_in"] or "",
                prompt_en=item["prompt_en"] or "",
                prompt_eq=item["prompt_eq"] or "",
                thumbnail=await UrlUtil.to_absolute_url(item["thumbnail"]),
                image_ref=await UrlUtil.to_absolute_url(item["image_ref"]),
                image_loc=await UrlUtil.to_absolute_url(item["image_loc"]),
                image_url=await UrlUtil.to_absolute_url(item["image_url"]),
                image_id=item["image_id"],
                task_id=item["task_id"],
                points=item["points"],
                status=item["status"],
                is_free=item["is_free"],
                share_status=share_status,
                share_result=square.get("audit_result") or "",
                fail_reason=item["fail_reason"] or "",
                create_time=item["create_time"],
                able_cut=able.get("able_cut", False),
                able_actions=able.get("able_actions", [])
            ))

        _pager.lists = _lists
        return _pager

    @classmethod
    async def detection(cls, user_id: int, ids: List[str]) -> List[schema.DrawsRecordsVo]:
        """
        绘画记录检测

        Args:
            user_id (int): 用户ID
            ids (List[str]): 绘画记录编号列表

        Returns:
            List[schema.DrawsRecordsVo]

        Author:
            zero
        """
        if len(ids) <= 0:
            return []

        lists = await (DrawsRecordsModel
                       .filter(code__in=ids)
                       .filter(user_id=user_id)
                       .filter(is_delete=0)
                       .limit(100)
                       .all())

        # 广场查询
        record_ids = [item.id for item in lists]
        squares = await DrawsSquareModel.querySquareDictsByRecordId(record_ids)

        # 处理列表
        _lists = []
        for item in lists:
            # 绘图操作: ["upsample1", "upsample2", ...]
            able = cls._handle_able_actions(item.able_actions, item.create_time)
            # 广场状态: [-1=未分享,-2=被隐藏,0=待审核,1=通过,2=拒绝]
            square = squares.get(item.id, {})
            share_status = square.get("audit_status", -1)
            if share_status == 0 and square.get("is_enable") == 0:
                share_status = - 2

            _lists.append(schema.DrawsRecordsVo(
                code=item.code,
                engine=item.engine,
                type=item.type,
                scale=item.scale,
                model=item.model,
                version=item.version,
                prompt_in=item.prompt_in or "",
                prompt_en=item.prompt_en or "",
                prompt_eq=item.prompt_eq or "",
                thumbnail=await UrlUtil.to_absolute_url(item.thumbnail),
                image_ref=await UrlUtil.to_absolute_url(item.image_ref),
                image_loc=await UrlUtil.to_absolute_url(item.image_loc),
                image_url=item.image_url,
                image_id=item.image_id,
                task_id=item.task_id,
                points=item.points,
                status=item.status,
                is_free=item.is_free,
                share_status=share_status,
                share_result=square.get("audit_result") or "",
                fail_reason=item.fail_reason or "",
                create_time=TimeUtil.timestamp_to_date(item.create_time),
                able_cut=able.get("able_cut", False),
                able_actions=able.get("able_actions", []),
            ))
        return _lists

    @classmethod
    async def delete(cls, user_id: int, code: str) -> None:
        """
        绘画记录删除

        Args:
            user_id (int): 用户ID
            code (str): 记录编号

        Author:
            zero
        """
        record = await (DrawsRecordsModel
                        .filter(code=code)
                        .filter(user_id=user_id)
                        .filter(is_delete=0)
                        .get())

        if record.status == 1:
            raise AppException("图片正在生成中,无法进行删除")

        await DrawsRecordsModel.filter(id=record.id).update(
            is_delete=1,
            delete_time=int(time.time())
        )

        await DrawsSquareModel.filter(record_id=record.id).update(
            is_delete=1,
            delete_time=int(time.time())
        )

    @classmethod
    async def square(cls, user_id: int, code: str) -> None:
        """
        绘画广场公开

        Args:
            user_id (int): 用户ID
            code (str): 记录编号

        Author:
            zero
        """
        record = await DrawsRecordsModel.filter(user_id=user_id, code=code).first()
        if record is None:
            raise AppException("记录不存在")

        square = await DrawsSquareModel.filter(record_id=record.id).first()
        if record.is_delete:
            if square is None or square.is_delete:
                raise AppException("记录不存在")

        if square is None:
            config = await ConfigUtil.get("square", "draws", {})
            audit_type = int(config.get("audit_type", 0))
            await DrawsSquareModel.create(
                source=2,
                cate_id=0,
                draw_code=record.code,
                operate_id=user_id,
                record_id=record.id,
                thumbnail=record.thumbnail,
                image_loc=record.image_loc,
                prompt_in=record.prompt_in or "",
                prompt_en=record.prompt_en or "",
                public_sum=1,
                audit_result="",
                audit_status=audit_type,
                is_enable=1,
                create_time=int(time.time()),
                update_time=int(time.time())
            )
        else:
            if square.is_delete:
                await DrawsSquareModel.filter(id=square.id).update(
                    public_sum=square.public_sum + 1,
                    is_delete=0,
                    delete_time=0
                )
            else:
                await DrawsSquareModel.filter(id=square.id).update(
                    is_delete=1,
                    delete_time=int(time.time())
                )

    @classmethod
    async def collect(cls, user_id: int, code: str) -> None:
        """
        绘画记录收藏

        Args:
            user_id (int): 用户ID
            code (str): 记录编号

        Author:
            zero
        """
        record = await DrawsRecordsModel.filter(user_id=user_id, code=code).first()
        if record is None:
            raise AppException("记录不存在")

        collect = await DrawsCollectModel.filter(user_id=user_id, record_id=record.id).first()
        square = await DrawsSquareModel.filter(record_id=record.id).first()
        if square is None:
            if collect is None or collect.is_delete:
                raise AppException("记录不存在")

        if collect is None:
            await DrawsCollectModel.create(
                user_id=user_id,
                record_id=record.id,
                total_num=1,
                create_time=int(time.time()),
                update_time=int(time.time())
            )
        else:
            if collect.is_delete:
                await DrawsCollectModel.filter(id=collect.id).update(
                    total_num=collect.total_num + 1,
                    is_delete=0,
                    delete_time=0
                )
            else:
                await DrawsCollectModel.filter(id=collect.id).update(
                    is_delete=1,
                    delete_time=int(time.time())
                )

    @classmethod
    def _handle_able_actions(cls, actions: str, create_time: int) -> dict:
        """
        绘图记录操作状态

        Args:
            actions (str): 操作类型: ["upsample1", "upsample2"]
            create_time (int): 记录时间

        Returns:
            dict

        Author:
            zero
        """
        able_cut = False
        able_actions = json.loads(actions or "[]")

        if isinstance(able_actions, list):
            if "low_variation" not in able_actions:
                able_cut = True
            if "variation_subtle" in able_actions:
                able_actions = [
                    "high_variation",
                    "low_variation",
                    "outpaint_1.5x",
                    "outpaint_2x",
                    "pan_down",
                    "pan_left",
                    "pan_right",
                    "pan_up",
                    "upscale_subtle",
                    "upscale_creative",
                ]

        if int(time.time()) > create_time + 3 * 60 * 60:
            able_actions = []

        return {"able_cut": able_cut, "able_actions": able_actions}
